Effective Java 2.0_中文版_Item 4

文章作者:Tyan
博客:noahsnail.com  |  CSDN  |  简书

Item 4: 用私有构造函数强制不能实例化

有时你会想写一个只包含一组静态方法和静态变量的类。这种类的名声很不好,因为有些人滥用它们来避免思考如何面向对象,但它们确实是有用的。它们可以用来以java.lang.Mathjava.util.Arrays的方式来组织与基本类型或数组相关的方法。它们也可以用来以java.util.Collections的方式来组织实现特定接口对象的静态方法,包括工厂方法(Item 1)。最后,它们可以用来组织一个fianl类的方法,从而代替扩展这个类。

这种工具类被设计成不能实例化:它的实例是没有意义的。然而,在缺少显式构造函数的情况下,编译器会提供一个公有的无参构造默认函数。对用户而言,这个构造函数与其它的构造函数没有任何差别。在发布的APIs中看到无意义的可实例化类是很罕见的。

企图通过声明一个类为抽象类来强制类不能被实例化是行不通的。这个类可以被子类化,子类可以被实例化。而且,它会使用户误认为这个类是为继承而设计的(Item 17)。然而有一些简单的习惯用法可以确保类不能被实例化。如果一个类没有显式的构造函数,会产生默认的构造函数,因此,一个含有私有构造函数的类不能被实例化:

1
2
3
4
5
6
7
8
// Noninstantiable utility class
public class UtilityClass {
// Suppress default constructor for noninstantiability
private UtilityClass() {
throw new AssertionError();
}
... // Remainder omitted
}

因为显式构造函数是私有的,因此类的外部不能访问构造函数。AssertionError不是必须的,但它可以避免类内部无意的调用构造函数。这种习惯用法有点违背直觉,似乎构造函数的提供就是为了它不能被调用一样。因此明智的做法是在类中加上注释,像上面的例子一样。

这种习惯用法的一个副作用就是阻止了类的子类化。子类的所有的构造函数必须调用父类的构造函数,无论是显式的或隐式的,但这种情况下子类不能调用父类构造函数。

如果有收获,可以请我喝杯咖啡!